export interface CodeGeneratorInterface {
	_id: string
	_name: string
	hasChild: boolean
	children: CodeGeneratorInterface[]
	prefix: string
	suffix: string
	childPrefix: string
	childSuffix: string
	genCode(): Promise<string>
}

export class CodeGenerator implements CodeGeneratorInterface {
	_id: string
	_name: string
	hasChild: boolean
	prefix: string
	suffix: string
	children: CodeGeneratorInterface[]
	childPrefix: string
	childSuffix: string
	constructor(name: string = 'CodeGenerator') {
		this.prefix = ''
		this.suffix = ''
		this.children = []
		this.hasChild = false
		this.childPrefix = ''
		this.childSuffix = ''
		this._name = name
		this.genId()
	}
	genId() {
		this._id = this._name + '_' + Date.now().toFixed(0) + '_'+ (Math.random() * 1000).toFixed(0).padStart(3, '0')
	}
	async genCode(): Promise<string> {
		var content = ''
		if(this.hasChild) {
			var childContentList = await Promise.all(this.children.map(async (child) => {
				return await child.genCode()
			}))
			childContentList.forEach((childContent: string) => {
				content += this.childPrefix + childContent + this.childSuffix
			})
		}
		return Promise.resolve(this.prefix + content + this.suffix) 
	}

	addChild(child: CodeGeneratorInterface) {
		this.children.push(child)
		this.hasChild = true
	}
}

export class PropertyCodeGenerator extends CodeGenerator {
	name: string
	value: string
	constructor(name: string, value: string) {
		super('PropertyCodeGenerator')
		this.name = name
		this.value = value
		this.prefix = ` ${this.name}="${this.value}"`
	}
}

export class Property {
	name: string
	value: string
	constructor(name: string, value: string) {
		this.name = name
		this.value = value
	}
}

export class TagCodeGenerator extends CodeGenerator {
	name: string
	properties: Property[]
	closeTag: boolean
	tabCount: number
	constructor(name: string, properties: Property[], closeTag: boolean = false, tabCount: number = 0) {
		super('TagCodeGenerator')
		this.name = name
		this.properties = properties
		this.closeTag = closeTag
		this.tabCount = tabCount
		this.encode()
	}

	addChild(child: CodeGeneratorInterface): void {
			super.addChild(child)
			this.encode()
	}

	async encode() {
		if(this.closeTag) {
			this.hasChild = false
			this.children = []
		}
		if(this.children.length > 0) {
			this.hasChild = true
		}
		var tab = Array(this.tabCount).fill('\t').join('')
		if (this.hasChild) {
			this.childPrefix = '\n'
		}
		if(this.tabCount > 1) {
			this.prefix += tab
		}
		var properties = (await Promise.all(this.properties.map(async (item) => await new PropertyCodeGenerator(item.name, item.value).genCode()))).join('')
		this.prefix =  `${tab}<${this.name}${properties}${this.closeTag ? '/>' : '>'}`
		this.suffix = this.closeTag ? '' :   `${this.hasChild ? `\n${tab}` : ''}</${this.name}>`
	}
}
